import GameFrameworkModule from "../Base/GameFrameworkModule";
import {ITaskManager} from "./ITaskManager";
import {TaskBase} from "./TaskBase";
import LinkListNode, {LinkList} from "../../Utils/LinkList";
import {TaskStatus} from "./TaskStatus";
import {ReferencePool} from "../Base/ReferencePool/ReferencePool";
import ccclass = cc._decorator.ccclass;
@ccclass("TaskManager")
export class TaskManager implements ITaskManager,GameFrameworkModule{

    private readonly  _tasks:LinkList<TaskBase>;
    private _serial:number;

    constructor() {
        this._tasks = new LinkList<TaskBase>();
        this._serial = 0;
    }

    CancelAllTasks(reason: string): void {
        this._tasks.ForEach(task => {
            if (task.status != TaskStatus.Waiting && task.status != TaskStatus.Running)
            {
                return false;
            }
            task.OnCancel(reason);
            return false;
        });
    }

    CancelTask(serialId: number | TaskBase, reason?: string): boolean {
        let flag:boolean = false;
        this._tasks.ForEach(value => {
            if(typeof serialId === "number"){
                if (value.serialId != serialId)
                {
                    return false;
                }
            }
            else{
                if (value.serialId != serialId.serialId)
                {
                    return false;
                }
            }
            if (value.status != TaskStatus.Waiting && value.status != TaskStatus.Running)
            {
                return false;
            }
            flag = true;
            value.OnCancel(reason);
            return true;
        })
        return flag;
    }

    Count(): number {
        return this._tasks.Size();
    }

    GenerateTask<T extends TaskBase>(type:(new ()=>T),priority: number = TaskBase._DefaultPriority): T {
        let task:T = ReferencePool.Acquire(type);
        task.Initialize(++this._serial, priority);
        task.OnGenerate();

        let current: LinkListNode<TaskBase> = this._tasks.First;
        while (current != null)
        {
            if (task.priority > current.Value.priority)
            {
                break;
            }

            current = current.Next;
        }

        if (current != null)
        {
            this._tasks.AddBefore(current, task);
        }
        else
        {
            this._tasks.AddLast(task);
        }

        return task;
    }

    get Priority(): number {
        return 930;
    }

    Shutdown(): void {
        this.CancelAllTasks(null);
        this._tasks.ForEach(value => {
            ReferencePool.Release(value);
            return false;
        });
        this._tasks.Clear();
    }

    Update(elapseSeconds: number, realElapseSeconds: number): void {
        let current:LinkListNode<TaskBase> = this._tasks.First;
        while (current != null)
        {
            let task:TaskBase = current.Value;
            if (task.status == TaskStatus.Free)
            {
                throw new Error("Task status is invalid.");
            }

            if (task.status == TaskStatus.Waiting)
            {
                task.OnStart();
            }

            if (task.status == TaskStatus.Running)
            {
                task.OnUpdate(elapseSeconds, realElapseSeconds);
                current = current.Next;
            }
            else
            {
                let next = current.Next;
                this._tasks.Remove2(current);
                ReferencePool.Release(task);
                current = next;
            }
        }
    }

    get baseName(): string {
        return "GameFrameworkModule";
    }

}